package main

import (
	"errors"
	"fmt"
	"net/http"
	"net/rpc"
)

/*
一次客户机对服务器的RPC调用,其内部操作大致有如下十步：
1.调用客户端句柄；执行传送参数
2.调用本地系统内核发送网络消息
3.消息传送到远程主机
4.服务器句柄得到消息并取得参数
5.执行远程过程
6.执行的过程将结果返回服务器句柄
7.服务器句柄返回结果，调用远程系统内核
8.消息传回本地主机
9.客户句柄由内核接收消息
10.客户接收句柄返回的数据

Go标准包中已经提供了对RPC的支持，而且支持三个级别的RPC：TCP、HTTP、JSONRPC。但Go的RPC包是独一无二的RPC，它和传统的RPC系统不同，
它只支持Go开发的服务器与客户端之间的交互，因为在内部，它们采用了Gob来编码。
Go RPC的函数只有符合下面的条件才能被远程访问，不然会被忽略，详细的要求如下：
 函数必须是导出的(首字母大写)
 必须有两个导出类型的参数，
 第一个参数是接收的参数，第二个参数是返回给客户端的参数，第二个参数必须是指针类型的
 函数还要有一个返回值error
正确的RPC函数格式如下：
func (t *T) MethodName(argType T1, replyType *T2) error :T、T1和T2类型必须能被encoding/gob包编解码。
*/

type Args struct {
	A, B int
}

type Quotient struct {
	Quo, Rem int
}

type Arith int

func (t *Arith) Multiply(args *Args, reply *int) error {
	*reply = args.A * args.B
	return nil
}

func (t *Arith) Divide(args *Args, quo *Quotient) error {
	if args.B == 0 {
		return errors.New("divide by zero")
	}
	quo.Quo = args.A / args.B
	quo.Rem = args.A % args.B
	return nil
}

/*
服务端
*/
func main() {
	arith := new(Arith)
	rpc.Register(arith)
	rpc.HandleHTTP()

	err := http.ListenAndServe(":9899", nil)
	if err != nil {
		fmt.Println(err.Error())
	}
}
